package excel;

import excel.annotation.Excel;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Author: 郑钰君
 * Date: 2022/4/19 14:47
 * FileName: excelUtils
 * Description:
 */
@Slf4j
public class excelUtils {

    /**
     * @description 解析表头数据，返回表头与其对应的列下标
     * @author 郑钰君
     * @date 2022/4/19 12:14
     * @param row 标头行
     * @param colUpperLimit 列的上限
     * @return Map<String, Integer>  key: 标头    val: 对应的下标
     */
    public static Map<String, Integer> getTableHeadAndColIndexMap(Row row, Integer colUpperLimit){
        Map<String, Integer> resMap = new HashMap<>();

        if (row == null || colUpperLimit < 0){
            return resMap;
        }

        for (int i = 0; i < colUpperLimit; i++) {
            String val = row.getCell(i).getStringCellValue();

            //表头信息不能重复
            if (resMap.containsKey(val)){
                log.error("表头信息“" + val + "”重复");
                throw new RuntimeException("表头信息异常");
            }
            resMap.put(val, i);
        }

        return resMap;
    }

    /**
     * @description 将表头映射转换为字段映射
     *              1.若没有找到字段对应的tableHead 默认抛弃该字段
     *              2.若tableHead没有对应的字段 默认抛弃此tableHead
     * @author 郑钰君
     * @date 2022/4/19 13:20
     * @param tableHeadMap
     * @param clazz
     * @return Map<Integer>
     */
    public static Map<Field, Integer> fieldMapAdapter(Map<String, Integer> tableHeadMap, Class clazz){
        Map<String, Field> fieldMap = getFieldMap(clazz);

        /**
         * 将字段名 与 tableHead 进行映射
         */
        Map<Field, Integer> resMap = new HashMap<>();
        if (!fieldMap.isEmpty()) {
            for (String key : fieldMap.keySet()) {
                Integer colIndex = tableHeadMap.get(key);
                if (colIndex != null) {
                    resMap.put(fieldMap.get(key), colIndex);
                }
            }
        }
        return resMap;
    }

    /**
     * @description
     * @author 郑钰君
     * @date 2022/4/19 15:22
     * @param sheet
     * @param tableHeadRowIndex 表头行
     * @param clazz 转换的实体类
     * @return List<T>
     */
    public static<T> List<T> input(Sheet sheet, Integer tableHeadRowIndex, Class<T> clazz) throws Exception {
        List<T> resList = new ArrayList<>();

        if (sheet == null || tableHeadRowIndex < 0 || clazz == null){
            log.info("sheet，表头行，实体类中有无效信息");
            return resList;
        }

        //表头行
        Row tableHeadRow = sheet.getRow(tableHeadRowIndex);
        Integer colUpperLimit = tableHeadRow.getPhysicalNumberOfCells();
        Integer rowUpperLimit = sheet.getPhysicalNumberOfRows();

        /**
         * 获取字段与表头下标的映射
         */
        Map<String, Integer> tableHeadMap = getTableHeadAndColIndexMap(tableHeadRow, colUpperLimit);
        if (tableHeadMap.isEmpty()){
            return resList;
        }
        Map<Field, Integer> fieldMap = fieldMapAdapter(tableHeadMap, clazz);
        if (fieldMap.isEmpty()){
            return resList;
        }

        /**
         * 实体转换
         * 默认从表头的下一行开始
         */
        for (int i = tableHeadRowIndex+1; i < rowUpperLimit; i++) {
            T entity = clazz.newInstance();
            Row row = sheet.getRow(i);

            for (Field field : fieldMap.keySet()){
                field.setAccessible(true);
                Integer colIndex = fieldMap.get(field);

                Cell cell = row.getCell(colIndex);
                if (cell == null){
                    continue;
                }

                String cellVal = CommonUtils.getCellValues(cell);

                CommonUtils.handleFields(entity, field, cellVal);
            }

            resList.add(entity);
        }

        return resList;
    }

    public static<T> void output(Sheet sheet, Integer tableHeadRowIndex, List<T> entityList, Class<T> clazz) throws IllegalAccessException {
        Map<String, Field> fieldMap = getFieldMap(clazz);
        if (fieldMap.isEmpty()){
            return;
        }

        /**
         * 设置表头行
         */
        Row tableHeadRow = sheet.createRow(tableHeadRowIndex);
        int colIndex = 0;
        for (String key : fieldMap.keySet()){
            tableHeadRow.createCell(colIndex++).setCellValue(key);
        }

        if (entityList.isEmpty()){
            return;
        }
        /**
         * 填写数据
         */
        int rowIndex = tableHeadRowIndex+1;
        for (T entity : entityList) {
            Row row = sheet.createRow(rowIndex++);
            colIndex = 0;
            for (String key : fieldMap.keySet()){
                Field field = fieldMap.get(key);
                field.setAccessible(true);
                Object cellValObj = field.get(entity);
                if (cellValObj != null){
                    row.createCell(colIndex).setCellValue(cellValObj.toString());
                }
                colIndex++;
            }
        }

        return;
    }


    /**
     * @description 获取clazz 所有带有@Excel的字段名   key:tableHead  val:Field
     * @author 郑钰君
     * @date 2022/4/20 15:14
     * @param clazz
     * @return Map<Field>
     */
    public static Map<String, Field> getFieldMap(Class clazz){
        Field[] fields = clazz.getDeclaredFields();
        Map<String, Field> fieldMap = new HashMap<>();
        for (Field field : fields){
            if (field.isAnnotationPresent(Excel.class)){
                String tableHead = field.getAnnotation(Excel.class).value();
                fieldMap.put(tableHead,field);
            }
        }
        return fieldMap;
    }

}
